import React from 'react';
import { connect } from 'dva';
import BaseComp from '../Base/BaseComp';
import TableComp from '../TableComp';
import isFunction from 'lodash-es/isFunction';
import SearchQuery from '../SearchComp';
import {omit, map, pick, forEach, unionWith, filter, findIndex, indexOf, uniq, trim} from 'lodash-es';
import { getOS, getRandomKey, getStorage, OrderField, QueryDataConf, QueryFilter } from 'jh-utils';
import { isArray, isObject, omitBy, isEmpty } from 'lodash-es';
import PropTypes from 'prop-types';
import { ComponentType } from '../Config';
import { queryApi } from '../Config/GlobalApi';
import StatusBoard from './StatusBoard';
import { Table, Radio } from 'antd';

const tmpOsObj = getOS();
const isPC = tmpOsObj.isPc;

/**
 * 查询列表组件
 */
export class QueryTable extends BaseComp {

    static propTypes = {
        ...BaseComp.propTypes,
        /**
         * 请求列表数据
         * @param searchData object 筛选条件。即 data_query/query 接口需要的参数(数据结构见 SearchComp/queryJson 文件)
         * @return {Promise}
         */
        fetchList: PropTypes.func,
        /**
         * 是否需要分页
         * @default true
         */
        isPagination: PropTypes.bool,
        /**
         * 筛选条件配置
         * [{compLabel:'会计科目',
            componentType: 'FIDER',
            fieldName: 'item'}]
         */
        filterConfig: PropTypes.arrayOf(PropTypes.object),
        /**
         * 筛选组件的属性
         */
        searchProps: PropTypes.object,
        /**
         * 是否由界面设计器自动渲染。默认是。
         *  false：作为普通组件使用
         */
        isTpl: PropTypes.bool,

        /**
         * 列表是否显示搜索框
         */
        isSearchInput: PropTypes.bool,
        /**
         * 查询到列表数据之后的回调
         * @param rsp
         */
        afterFetchList: PropTypes.func,
        /**
         * 是否需要搜索组件
         */
        needSearch: PropTypes.bool,
    };

    static defaultProps = {
        isPagination: true,
        isTpl: true,
        isSearchInput: true,
        needSearch: true,
    };

    compKey = getRandomKey();

    /**
     * 筛选条件
     * fuzzyMatch?: '模糊搜索的字段，用","分隔',
     * search?: 模糊搜索的值,
     * filterData?: 过滤条件，可通过 formatFilter(filterData) 生成 data_query/query 接口的 fitler 参数,
     * current?: number,
     * pageSize?:number
     * @type {{fuzzyMatch?: string, search?: string, filterData?: object, current?: number, pageSize?:number }}
     */
    searchData = {};
    searchRef;
    /**
     * @type {TableComp}
     */
    tableRef;
    /**
     * 过滤条件。QueryFilter 的实例
     * @type {QueryFilter}
     */
    filter = null;

    /**
     * 流程代办过滤条件
     * @type {QueryFilter}
     */
    actInfoFilter = null;

    /**
     * 表格的“行-事件处理函数”
     * @type {{onClick?: function({record: {key: string, id: number}}), onDoubleClick?:function({record: {key: string, id: number}})}}
     */
    rowHandlers = {};

    constructor(props) {
        super(props);

        const pageObj = props.isPagination ? {
            current: 1,
            pageSize: this.state.page.pageSize || 40,
        } : {};
        this.searchData = { ...pageObj, fuzzyMatch: 'code,name,spellCode' };
    }


    initState(props) {
        const iState = super.initState(props);
        const reState = {
            ...iState,
            loading: false,
            list: [],
            type: 'list', // 功能类型切换
        };

        if (props.isPagination) {
            reState.page = {
                total: 0, // 总记录数
                pageSize: 40, // 每页显示的记录数
                current: 1, // 当前页
                pages: 0, // 总页数
            };
        }
        return reState;
    }

    componentDidMount() {
        super.componentDidMount && super.componentDidMount();
        // 将本组件的实例存到 appins 的 qtIns 变量中，用于被 appins 在必要时调用
        const { appins, isTpl } = this.props;
        if (!!isTpl && appins && isFunction(appins.setByKeyValue)) {
            appins.setByKeyValue('qtIns', this);
        }
        // this.fetchList();
    }

    /**
     * 获取列表数据
     */
    fetchList() {
        let fAppCode = this.getAppCode();
        let listFunc = this.getFromPropAppins('fetchList');
        if (!isFunction(listFunc)) {
            listFunc = this.fetchListFunc.bind(this);
        }

        if (fAppCode && isFunction(listFunc)) {
            const { isPagination } = this.props;
            let ajaxData = this.getAjaxData4List();

            this.setState({ loading: true });
            const fetchPromise = listFunc(ajaxData, {}, this);

            if (fetchPromise instanceof Promise) {
                fetchPromise.then((rsp) => {
                    const newState = { loading: false };

                    if (rsp && rsp.status === 200) {
                        let rspData = rsp.data || {};
                        newState.list = isArray(rspData) ? rspData : (rspData.results || rspData.records);

                        newState.list = map(newState.list, (item) => ({
                            key: item.id,
                            ...item,
                        }));

                        if (isPagination) {
                            newState.page = {
                                total: rspData.resultCount,
                                pageSize: rspData.maxResults,
                                current: this.searchData.current,
                            };
                        }

                    }
                    this.setState(newState, () => {
                        this.runPropsFunc('afterFetchList')(rsp);
                    });
                    return rsp;
                }).catch(() => {
                    this.setState({ loading: false });
                });
            } else {
                this.setState({ loading: false });
            }
        }

    }

    fetchListFunc(ajaxData) {
        return this.request(queryApi, ajaxData);
    }

    addActivityFilter(searchData) {
        this.actInfoFilter = this.getActivityFilter(searchData);
    }

    getActivityFilter(searchData) {
        const filter = new QueryFilter(QueryFilter.AND);
        // const filter = this.filter && this.filter.toJson ? this.filter.copy() : new QueryFilter(QueryFilter.AND);
        const fAppCode = this.getAppCode();
        const accountInfo = getStorage('accountInfo') || {};
        const { corpCode = '', userId = '' } = accountInfo;
        if (!isEmpty(searchData) && searchData.activity) {
            const activity = searchData.activity;
            switch (activity) {
                case 'END':
                    // filter.andEqual('activityInfo.taskCode', 'end');
                    const hqlEND = '(SELECT i.dataId FROM com.jianhui.act.engine.domain.ActivityInstanceProgress p JOIN p.instance i ' +
                        `WHERE i.appCode='${fAppCode}' AND p.status='TREATED' AND p.updateInfo.userId=${userId} GROUP BY i.dataId)`;
                    filter.andIn('id', hqlEND);
                    break;
                case 'TODO':
                    filter.andIsNotNull('activityInfo.taskKey');
                    filter.andNotEqual('activityInfo.taskKey', '');
                    filter.andNotEqual('activityInfo.taskKey', 'start');
                    filter.andNotEqual('activityInfo.taskKey', 'end');
                    if (!isEmpty(searchData.activityTaskCode) && searchData.activityTaskCode !== 'all') {
                        filter.andEqual('activityInfo.taskCode', searchData.activityTaskCode);
                    }
                    const hql = '(SELECT it.id FROM ActivityInstanceActor it ' +
                        'JOIN it.instance i WHERE i.dataId=o.id AND i.currentTask=o.activityInfo.taskKey ' +
                        `AND it.taskKey=i.currentTask AND i.appCode='${fAppCode}' ` +
                        'AND i.procDefKey=o.activityInfo.procDefKey ' +
                        'AND it.taskCode=o.activityInfo.taskCode ' +
                        `AND it.actor.id=${userId} )`;
                    filter.andExists(hql);
                    break;
                default:
                    break;
            }
        }
        return filter;
    }

    /**
     * 获取“请求列表数据”的参数
     * @return {{filter: any, filterIns: QueryFilter, queryFields: [string], appCode: string, searchData: {fuzzyMatch?: string, search?: string, filterData?: Object, current?: number, pageSize?: number}}}
     */
    getAjaxData4List() {
        const { fuzzyMatch, appins, isPagination, colsConf, sortConf, filterConfig } = this.props;
        let propFilter = this.getPropsByName('filter') || this.filter;
        let fAppCode = this.getAppCode();

        let searchFuzzyMatch = fuzzyMatch ? fuzzyMatch : (
            appins && appins.fuzzyMatch ? appins.fuzzyMatch : this.searchData.fuzzyMatch
        );
        // 从“高级”配置项取出“查找器、文本”类型的搜索字段，也作为模糊搜索字段
        let filterFuzzyMatch = [];
        forEach(filterConfig, (fConf) => {
            if (fConf && fConf.fieldName) {
                if (ComponentType.FINDER === fConf.componentType) {
                    let fName = fConf.fieldName;
                    if (fName) {
                        let tmpArr = fName.split('.');
                        if ('id' === tmpArr[tmpArr.length - 1]) {
                            tmpArr.pop();
                        }
                        fName = tmpArr.join('.');
                    }
                    filterFuzzyMatch.push(
                        `${fName}.code`,
                        `${fName}.name`,
                        `${fName}.spellCode`,
                    );
                } else if ([ComponentType.TEXT_INPUT, ComponentType.TEXT_AREA].indexOf(fConf.componentType) > -1) {
                    filterFuzzyMatch.push(fConf.fieldName);
                }
            }
        });
        if (!isEmpty(filterFuzzyMatch)) {
            searchFuzzyMatch += ',' + filterFuzzyMatch.join(',');
        }
        searchFuzzyMatch = uniq(searchFuzzyMatch.split(',')).join(',');

        let queryConf = new QueryDataConf();
        queryConf.appCode = fAppCode;
        queryConf.queryFields.push('id');

        queryConf.filter = propFilter && propFilter.toJson ? propFilter.copy() : new QueryFilter(QueryFilter.AND);
        if (this.actInfoFilter) {
            queryConf.filter.children.push(this.actInfoFilter);
        }
        queryConf.filter.formatBySearchData({
            ...this.searchData,
            fuzzyMatch: searchFuzzyMatch,
        });
        // 排序
        //
        if (isArray(sortConf)) {
            forEach(sortConf, (sortItem) => {
                queryConf.orderFields.push(new OrderField(sortItem.name, sortItem.sort === 0 ? 'ASC' : 'DESC'));
            });
        }
        // 自定义过滤条件
        this.customQueryConf(queryConf);

        let ajaxData = queryConf.toJson();
        ajaxData.filterIns = queryConf.filter;
        ajaxData.searchData = this.searchData;

        if (isArray(colsConf)) {
            forEach(colsConf, (colItem) => {
                if (colItem && ComponentType.EXPRESSION !== colItem.componentType && false !== colItem.IS_META_DATA) {
                    ajaxData.queryFields.push(colItem.name);
                }
            });
        }

        let { viewConfig = {} } = appins || {};
        // 是否需要状态看板
        if (viewConfig && viewConfig.stateEnable) {
            ajaxData.queryFields.push('state');
        }

        ajaxData.queryFields = uniq(ajaxData.queryFields);

        if (isPagination) { // 分页
            let { current, pageSize } = this.searchData;

            if (current) {
                ajaxData.startIndex = (pageSize * (current - 1)) || 0;
                ajaxData.maxResults = pageSize || 40;
            }
        }
        return ajaxData;
    }

    /**
     * 自定义过滤条件
     * @param queryConf {QueryDataConf} 过滤条件配置。直接修改这个参数即可
     */
    customQueryConf(queryConf) {
        this.runPropsFunc('customQueryConf')(queryConf);
    }

    /**
     * 设置“列渲染”
     * @param fieldName {string}
     * @param render {function(value, record, rowIndex)}
     */
    setColRender(fieldName, render) {

        if (this.tableRef && isFunction(this.tableRef.setColRender)) {
            return this.tableRef.setColRender(fieldName, render);
        }
    }

    /**
     * 设置【列表页】表格“行-事件响应”
     * @param handlers {{onClick?: function({record: {key: string, id: number}}), onDoubleClick?:function({record: {key: string, id: number}})}}
     * @param isWholeObject Boolean 是否重新设置整个 rowHandlers 对象，默认 false
     *                      true: 以 handlers 重新设置 rowHandlers ;
     *                      false: 保留原有设置，只做部分替换;
     */
    setRowHandlers(handlers, isWholeObject = false) {
        if (isWholeObject) {
            this.rowHandlers = handlers;
        } else {
            this.rowHandlers = { ...this.rowHandlers, ...handlers };
        }
    }

    /**
     * 设置搜索条件数据 searchData
     * @param newSearchData Object 新的搜索条件
     * @param isWholeObject Boolean 是否重新设置整个 searchData 对象，默认 false
     *                      true: 以 newSearchData 重新设置 searchData ;
     *                      false: 保留原有数据，只做字段替换;
     */
    setSearchData(newSearchData, isWholeObject = false) {
        if (isObject(newSearchData)) {
            if (isWholeObject) {
                this.searchData = { ...newSearchData };
            } else {
                let filterData = this.searchData.filterData || {};
                let newFilterData = newSearchData.filterData || {};
                this.searchData = {
                    ...this.searchData,
                    ...newSearchData,
                    filterData: { ...filterData, ...newFilterData },
                };
            }

            this.searchData = omitBy(this.searchData, (sItem) => ('undefined' === typeof sItem || null === sItem || '' === sItem));
        }
    }

    /**
     * 设置已选中记录的 key 数组
     * @param selectedRowKeys {[]} 已选中的记录 key 数组
     * @param afterCb
     */
    setSelectedKeys(selectedRowKeys, afterCb) {
        this.selectedRows = filter(this.selectedRows, (row) => (row && indexOf(selectedRowKeys, row.key) > -1));

        if (this.tableRef && this.tableRef.setSelectedKeys) {
            this.tableRef.setSelectedKeys(selectedRowKeys, afterCb);
        } else {
            afterCb && afterCb();
        }
    }

    /**
     * 已选中的记录
     * @type {*[]}
     * @private
     */
    _selectedRows = [];

    get selectedRows() {
        return this._selectedRows;
    }

    set selectedRows(value) {
        this._selectedRows = value;

        if (!!this.props.isTpl) { // 如果是作为界面设计器模板的组件使用，则实时设置 appins 的“已选中数据”
            const { appins } = this.props;
            if (appins && isFunction(appins.setByKeyValue)) {
                appins.setByKeyValue('selectedRows', this._selectedRows);
            }
        }
    }

    /**
     * 打开高级搜索浮层
     */
    openSearch(isOpen = true, afterCb = null) {
        if (this.searchRef) {
            this.searchRef.setState({ isOpen }, afterCb);
        }
    }

    /**
     * 当选中数据有变化时的回调
     * @param selectedRowKeys
     * @param selectedRows
     * @param moreProps
     */
    hdlChangeRowSel(selectedRowKeys, selectedRows, moreProps) {

        if (this.props.multi) {
            // rowSelection.onChange
            const { selected } = moreProps || {};

            if (selected) { // 如果是“选中操作”，将新选中的记录合并到 selectedRows
                this.selectedRows = unionWith(
                    this.selectedRows,
                    selectedRows,
                    (row1, row2) => (row1.id === row2.id),
                );
            } else { // 取消选中
                const { changeRows } = moreProps || {};
                this.selectedRows = filter(this.selectedRows, (row) => (
                    -1 === findIndex(changeRows, (cRow) => (cRow.id === row.id))
                ));
            }
        } else {
            this.selectedRows = selectedRows;
        }
        // 执行 props.rowSelection 的回调
        const { rowSelection } = this.props;
        if (rowSelection && rowSelection.onChange) {
            rowSelection.onChange(selectedRowKeys, this.selectedRows, moreProps);
        }
        // console.log(`QueryTable hdlChangeRowSel this.selectedRows:`, this.selectedRows);
    }

    /**
     * TableComp 组件有操作变化时的回调
     * @param pagination
     * @param filters
     * @param sorter
     * @param moreData
     */
    handleChangeTable = (pagination, filters, sorter, moreData) => {
        // console.log('qt handleChangeTable', pagination, filters, sorter, moreData);
        const { current, pageSize } = pagination;
        this.searchData.current = current;
        this.searchData.pageSize = pageSize;
        this.fetchList();
    };

    /**
     * 筛选条件区域的高度
     * @type {number}
     */
    get searchHeight() {
        if (this.searchRef && this.searchRef.getCompHeight) {
            return this.searchRef.getCompHeight();
        }
        return this.props.needSearch ? 70 : 0;
    }

    /**
     * 获取表格的 style 对象
     * @return {{}}
     */
    getTableHeight() {
        let { style } = this.props;
        let compHeight = style && style.height ? style.height : '600px';
        return 'auto' === compHeight ? 'auto' : `calc(100% - ${this.searchHeight}px)`;
    }

    hdlDBClickRow(record) {
        const { isTpl } = this.props;

        if (isFunction(this.rowHandlers.onDoubleClick)) {
            let tmpReturn = this.rowHandlers.onDoubleClick(record);
            if (false === tmpReturn) return false;
        }
        if (!!isTpl) {
            const { appins } = this.props;
            if (appins && isFunction(appins.jump2Detail)) {
                appins.jump2Detail(appins.appInfo ? appins.appInfo.code : '', record ? record.id : '');
            }
        }
    }

    listRender(context) {
        let { isPagination, pagination, rowSelection, style, isTpl, ...restProps } = this.props;

        const { page, list } = this.state;
        let tHeight = this.getTableHeight();

        pagination = false === isPagination ? false : {
            position: ['bottomCenter'],
            showQuickJumper: true,
            showSizeChanger: true,
            pageSizeOptions: [20, 40, 100],
            ...page,
            ...(pagination || {}),
        };
        const belong = { query: true, customprops: this.props.customprops };
        return (
            <TableComp
                bordered={false}
                needNO={true}
                {...omit(restProps, ['searchProps', 'style'])}
                onRef={(ref) => {
                    this.tableRef = ref;
                }}
                style={{ ...omit(style, ['width', 'height']), height: tHeight }}
                loading={this.state.loading}
                selecting={!!(restProps && restProps.rowSelect)}
                belong={belong}
                pagination={pagination}
                dataSource={list}
                onChange={this.handleChangeTable}
                onRowProps={{
                    onDoubleClick: (e, record) => { // 双击记录，调整到详情
                        return this.hdlDBClickRow(record);
                    },
                    onClick: (e, record) => {
                        // 如果是移动端，则在单机表格行时，触发“双击”操作
                        if (!isPC) {
                            let tmpRt = this.hdlDBClickRow(record);
                            if (tmpRt === false) return false;
                        }

                        if (isFunction(this.rowHandlers.onClick)) {
                            let tmpReturn = this.rowHandlers.onClick(record);
                            if (false === tmpReturn) return false;
                        }

                        if (!!isTpl && true !== this.props.rowSelect) {
                            const { appins } = this.props;
                            if (appins && isFunction(appins.setByKeyValue)) {
                                appins.setByKeyValue('selectedRows', [record]);
                            }
                        }
                    },
                }}
                rowSelection={{
                    ...(rowSelection || {}),
                    onChange: this.hdlChangeRowSel.bind(this),
                }}
            />
        );
    }

    /**
     * 状态看板
     * @param context
     * @constructor
     */
    StatusBoardRender(context) {
        let { isPagination, pagination, rowSelection, style, isTpl, ...restProps } = this.props;

        const { list } = this.state;
        let tHeight = this.getTableHeight();

        const belong = { query: true, customprops: this.props.customprops };
        return (
            <StatusBoard initList={list}
                         qtins={this}
                         appins={this.props.appins}
                         fetchList={this.fetchList.bind(this)}
                         onChange={this.handleChangeTable}
                         style={{ ...omit(style, ['width', 'height']), height: tHeight }}
                         belong={belong}/>
        );
    }

    mainRender(context) {
        let { filterConfig, queryTable, isTpl, needSearch, appins = {}, ...restProps } = this.props;
        let defaultParams = this.getAppCode() && !isEmpty(queryTable) && queryTable[this.getAppCode()];
        let compHeight = restProps.style && restProps.style.height ? restProps.style.height : '600px';
        let belong = { query: true, customprops: this.props.customprops };
        let searchMoreProps = {};
        let appCode = this.getAppCode();
        let { viewConfig = {} } = appins;

        if (!isTpl) {
            searchMoreProps.activityVisible = false; // 如果不是界面设计器渲染出来的，则不显示“我的、代办、已办”
        }

        return (
            <div style={{ ...pick(restProps.style, ['width']), height: compHeight, position: 'relative' }}
                 id={this.compKey}>
                {
                    false !== needSearch && (
                        <SearchQuery
                            onOk={(searchData, originValues) => {
                                // console.log('qt onOk', searchData);
                                if (this.props.onOk && isFunction(this.props.onOk)) {
                                    this.props.onOk(searchData, originValues);
                                    return false;
                                }
                                const data = {
                                    current: 1, // 从第一页开始
                                    filterData: {},
                                };
                                if (searchData) {
                                    data.search = trim(searchData.search);
                                    forEach(searchData.formData, (val, key) => {

                                        if (val && val.filterVal) {
                                            data.filterData[key] = val.filterVal;
                                        } else {
                                            data.filterData[key] = undefined;
                                        }
                                    });
                                    if (!!isTpl) {
                                        this.actInfoFilter = searchData.actInfoFilter;
                                    }
                                }
                                this.setSearchData(data);
                                // console.log('searchData', searchData);

                                this.fetchList();
                            }}
                            filterConfig={filterConfig}
                            appins={this.props.appins}
                            belong={belong}
                            {...this.props.searchProps}
                            {...searchMoreProps}
                            {...pick(this.props, ['defaultSearchData', 'isSearchInput'])}
                            onRef={(ref) => {
                                this.searchRef = ref;
                            }}
                            defaultParams={defaultParams} // 从别的页面传进的参数
                            popupContainId={this.compKey}
                        />
                    )
                }
                {
                    appCode && viewConfig && viewConfig.stateEnable &&
                    <div style={{ position: 'absolute', top: '6px', right: '10px' }}>
                        <Radio.Group value={this.state.type}
                                     type={'primary'}
                                     onChange={e => this.setState({ type: e.target.value })}>
                            <Radio.Button value="list">列表</Radio.Button>
                            <Radio.Button value="statusBoard">看板</Radio.Button>
                        </Radio.Group>
                    </div>
                }
                {
                    'statusBoard' === this.state.type && this.StatusBoardRender(context)
                }
                {
                    'list' === this.state.type && this.listRender(context)
                }
            </div>
        );
    }

}

export default connect(({ queryTable }) => ({ queryTable }))(QueryTable);